package com.neusoft.thread12local;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * ThreadLocal是指线程本地变量，不是指Thread
   ThreadLocal使用场合主要解决多线程中数据数据因并发产生不一致问题。也就是说如果想每个线程都在操作共享数据的时候不互相影响，但是又不想使用同步解决，那么ThreadLocal会是你的菜
   ThreadLocal实现线程隔离的核心在于为每个访问该值的线程都创建了一个ThreadLocalMap，这样不同的线程在操作共享数据时可以不互相影响
         与synchronized的区别：synchronized用于线程间的数据共享，而ThreadLocal则用于线程间的数据隔离。两者使用的领域不同，ThreadLocal并不是为了替代synchronized而出现的，而且ThreadLocal不能实现原子性，因为ThreadLocal的ThreadLocalMap的操作实际的作用范围是单线程，与多线程没有任何关系
         在多线程情况下使用ThreadLocal而创建的ThreadLocalMap是否会出现内存溢出：答案是不会。因为存储数据的Entry是弱引用，线程执行结束后会自动被垃圾回收。
 * @author Zhang.Yan
 *
 */
public class PersonThreadLocalDemo
{
	
	private static final ThreadLocal<Person> personLocal = new ThreadLocal<>();
    private static final Random ran = new Random();
    private static final DateFormat format = new SimpleDateFormat("HH:mm:ss");

    /**
     * 不同的线程并发修改Person的age属性
     */
    static class Wokrer implements Runnable
    {
        @Override
        public void run() 
        {
            doExec();
        }

        private void doExec() 
        {
            System.out.println(Thread.currentThread().getName() + " start task at "+ format.format(new Date()));
            //不同的线程会会将age属性设置成不同的值
            int age = ran.nextInt(20);
            Person p = getPerson();
            //设置年龄
            p.setAge(age);
            System.out.println(Thread.currentThread().getName() + ": set age to " + p.getAge() + " at "+ format.format(new Date()));
            try 
            {
                TimeUnit.SECONDS.sleep(2);
            }
            catch (InterruptedException e) 
            {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ": get age " + p.getAge() + " at "+ format.format(new Date()));
        }

        protected Person getPerson() 
        {
            Person p = personLocal.get();
            if (p == null)
            {
                p = new Person();
                personLocal.set(p);
            }
            return p;
        }
    }

    public static void main(String[] args)
    {
        Wokrer wokrer = new Wokrer();
        new Thread(wokrer,"worker-1").start();
        new Thread(wokrer,"worker-2").start();
    }
}


